/* 
 * Copyright 2011 kOSMik.
 * This file is part of kOSMik.
 * 
 * kOSMik is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * kOSMik is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with kOSMik.  If not, see <http://www.gnu.org/licenses/>.
 *  
 * kOSMik:
 * Open Street Map - Editor.
 * http://code.google.com/p/swp-dv-ws2010-osm-2/
 */

package de.fuberlin.kosmik.gui.view.adapter;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import de.fuberlin.kosmik.R;
import de.fuberlin.kosmik.StrUtils;
import de.fuberlin.kosmik.data.osmt.OsmtConstants;
import de.fuberlin.kosmik.data.osmt.OsmtData;
import de.fuberlin.kosmik.data.osmt.OsmtDataFactory;
import de.fuberlin.kosmik.data.osmt.OsmtElementRecord;
import de.fuberlin.kosmik.data.osmt.OsmtNode;
import de.fuberlin.kosmik.data.osmt.OsmtNodeRecord;
import de.fuberlin.kosmik.data.osmt.OsmtObjectException;
import de.fuberlin.kosmik.gui.activity.TagPickerActivity;
import de.fuberlin.kosmik.log.Constants;

/**
 * Acts as a bridge between (ListView) lstTagPickerListView in
 * {@code TagPickerActivity} and the underlying data for that view.
 * 
 * Fill the list with names of bundles ({@code OsmBundle})
 * 
 * @author Johannes
 * @see TagPickerActivity
 * 
 */
public class TagListAdapter extends ArrayAdapter<Integer> {
	private static final int TAG_LIST_ROW_LAYOUT = R.layout.tag_list_row;

	private final Activity activity;
	private static OsmtData osmtData = null;
	private final LayoutInflater layoutInflater;
	private final int osmtElementFilter;
	private int defaultImageResId;
	/** This HashMap caches all Nodes loaded once loaded from DB */
	// private static HashMap<Integer, OsmtNodeRecord> nodeRecords = new
	// HashMap<Integer, OsmtNodeRecord>();
	private static final HashMap<Integer, OsmtNodeRecord> nodeRecords = new HashMap<Integer, OsmtNodeRecord>();

	/**
	 * Constructor.
	 * 
	 * @param activity The current context
	 * @param osmtParentNodeId The parent node of all nodes in the list.
	 *            displayed
	 * @param osmtElementFilter The filter, that specify if will display only
	 *            nodes or ways or areas or a set of them
	 */
	public TagListAdapter(Activity activity, int osmtParentNodeId, int osmtElementFilter) {
		super(activity, TAG_LIST_ROW_LAYOUT, aquireItems(activity, osmtParentNodeId,
				osmtElementFilter));
		this.activity = activity;
		this.osmtElementFilter = osmtElementFilter;
		layoutInflater = LayoutInflater.from(activity);
		detectDefaultImageResId();
	}

	private static List<Integer> aquireItems(final Context context, final int osmtParentNodeId,
			final int osmtElementFilter) {

		class LoadNodesTask extends AsyncTask<List<Integer>, Void, Void> {

			@Override
			protected Void doInBackground(List<Integer>... lists) {
				if (lists.length > 0)
					for (Integer nodeId : lists[0]) {
						getNodeRecordWithNodeId(nodeId.intValue());
					}
				return null;
			}
		}

		if (osmtData == null)
			osmtData = OsmtDataFactory.createOsmtData(context);

		final List<Integer> nodeList = osmtData
				.fetchAllIdsOfChildNodesRelatedToParentIdFilteredByElements(osmtParentNodeId,
						osmtElementFilter);
		// pre load nodes data
		new LoadNodesTask().execute(nodeList);
		// acquire nodes to display in list
		return nodeList;
	}

	private void detectDefaultImageResId() {
		// detect default image
		if (OsmtElementRecord.isArea(osmtElementFilter)) {
			defaultImageResId = R.drawable.ic_area_light;
		} else if (OsmtElementRecord.isWay(osmtElementFilter)) {
			defaultImageResId = R.drawable.ic_way_light;
		} else {
			defaultImageResId = R.drawable.ic_poi_light;
		}
	}

	/**
	 * Record for the views in a row.
	 */
	public static class ListItem {
		/**
		 * That view display an image.
		 */
		public ImageView imageView;
		/**
		 * That view shows the display name of the bundle.
		 */
		public TextView textView;

		/**
		 * The node data record loaded from the Osmt-database
		 */
		public OsmtNodeRecord osmtNodeRecord;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {

		final View currentListItem;

		ListItem listItem;
		// fill text and image of item (row)
		if (convertView == null) {

			currentListItem = layoutInflater.inflate(TAG_LIST_ROW_LAYOUT, null, true);
			listItem = new ListItem();
			listItem.textView = (TextView) currentListItem.findViewById(R.id.label);
			listItem.imageView = (ImageView) currentListItem.findViewById(R.id.icon);
			currentListItem.setTag(listItem);
		} else {
			// if row-object already exists, use it
			currentListItem = convertView;
			listItem = (ListItem) currentListItem.getTag();
		}

		OsmtNodeRecord nodeRecord = getNodeRecordWithNodeId(getItem(position).intValue());
		if (nodeRecord != null) {
			listItem.osmtNodeRecord = nodeRecord;
			listItem.textView.setText(nodeRecord.displayName);
			listItem.imageView.setImageResource(defaultImageResId);
			if (StrUtils.isNotEmpty(nodeRecord.icon)) {
				final String iconName = OsmtConstants.URI_SJJB_IMAGES + nodeRecord.icon
						+ ".n.24.png";

				InputStream imageStream;
				try {
					imageStream = activity.getAssets().open(iconName);
					Bitmap bitmap = BitmapFactory.decodeStream(imageStream);
					listItem.imageView.setImageBitmap(bitmap);
				} catch (IOException e) {
					Log.w(Constants.TAG, "cannot load image from " + iconName, e);
				}

			} else {
				listItem.imageView.setImageResource(defaultImageResId);
			}
		} else {
			listItem.osmtNodeRecord = null;
			listItem.textView.setText("");
			listItem.imageView.setImageResource(defaultImageResId);
		}

		/*
		 * TODO: show an image left to the theme name // set corresponding icon
		 * of tag String tagName = tagNames[position].replaceAll( " ",
		 * "_").toLowerCase(); int iconResID =
		 * activity.getResources().getIdentifier( "osm_tag_" + tagName,
		 * "drawable", activity.getPackageName()); // only if an icon found,
		 * replace the default image if ( iconResID != 0)
		 * listItem.imageView.setImageResource( iconResID);
		 */
		// for better contrast toggle background of rows
		currentListItem.setBackgroundColor(position % 2 != 0 ? R.color.tracklist_element_odd
				: R.color.tracklist_element_even);

		return currentListItem;
	}

	/**
	 * Getter for cached Nodes.
	 * <p>
	 * If the node is not registered, the method try to load it from database.
	 * 
	 * @param nodeId The id of the node.
	 * 
	 * @return The data of node in a {@link OsmtNodeRecord}, if the node was
	 *         ever loaded before. Otherwise null.
	 */
	public static OsmtNodeRecord getNodeRecordWithNodeId(final int nodeId) {
		OsmtNodeRecord nodeRecord = nodeRecords.get(Integer.valueOf(nodeId));
		if (nodeRecord == null) {
			try {
				nodeRecord = new OsmtNode(osmtData, nodeId, null, null, null, null, null, null,
						null, null).get();
				cacheNodeRecord(nodeRecord);
			} catch (OsmtObjectException e) {
				nodeRecord = null;
			}
		}

		return nodeRecord;
	}

	/**
	 * Setter to cache a Node.
	 * 
	 * @param nodeRecord The Node data you want to cache.
	 * 
	 */
	public static void cacheNodeRecord(OsmtNodeRecord nodeRecord) {
		if (nodeRecord != null)
			nodeRecords.put(Integer.valueOf(nodeRecord.id), nodeRecord);
	}
}